package de.gameduell.framework.game.matching {
	import de.gameduell.framework.game.matching.ITile;
	import de.polygonal.ds.Set;	

	/**
	 * @author cbra
	 */
	public class Matcher {
		private var _minHorizontal:int;
		private var _minVertical:int;
		private var _searchedTiles:Set;
		private var _matches:Array;
		
		public function Matcher(horizontal:int,vertical:int) {
			_minHorizontal = horizontal;
			_minVertical = vertical;
			_matches = new Array();
			_searchedTiles = new Set();
		}
			
		public function clearMatches():void{
			_searchedTiles.clear();
			_matches.length = 0;
		}
		
		public function findDeepMatches(tile:ITile):Array{
			if(tile.token != null){
				clearMatches();
				var matches:Array = findDeepMatchesRecursiv(tile);
				if(matches.length > 0){
					matches.push(tile);
				}
				var cleanMatches:Set = new Set();		
				for each(var matchedTile:ITile in matches){
					cleanMatches.set(matchedTile);
				}
				return cleanMatches.toArray();
			}else{
				return new Array();
			}
		}
		
		public function findAllMatches(tiles:Array):Array{
			var allMatches:Set = new Set();		
			for each(var tile:ITile in tiles){
				var matches:Array = findDeepMatches(tile);
				for each(var matchedTile:ITile in matches){
					allMatches.set(matchedTile);
				}
			}
			return allMatches.toArray();	
		}

		
		public function findMatchesNear(tile:ITile):Array{	
			if(tile.token != null){
				clearMatches();
				return findDeepMatchesRecursiv(tile);
			}else{
				return new Array();
			}
		}
		
		private function findDeepMatchesRecursiv(tile:ITile):Array{
			var matches:Array = findMatchesNearRecursiv(tile);
			for(var i:* in matches){
				findDeepMatchesRecursiv(matches[i]);
			}
			return _matches;	
		}
		
		private function findMatchesNearRecursiv(aTile:ITile):Array{		
			var	result:Array = new Array();
			var rightMatches:Array = searchRight(aTile,new Array());
			var leftMatches:Array = searchLeft(aTile,new Array());
			var upMatches:Array = searchUp(aTile,new Array());
			var downMatches:Array = searchDown(aTile,new Array());	
			
			var horizontalMatches:Array = rightMatches.concat(leftMatches);
			var verticalMatches:Array = upMatches.concat(downMatches);
			
			var matched:Boolean = false;
			if(horizontalMatches.length >= _minHorizontal-1){
				result = result.concat(horizontalMatches);
				tagMatched(horizontalMatches);
				matched = true;
			}
			if(verticalMatches.length >= _minVertical-1){
				result = result.concat(verticalMatches);
				tagMatched(verticalMatches);
				matched = true;
			}
			if(matched){
				result = result.concat(aTile);
				tagMatched([aTile]);
			}
			return result;
		}
		
		public function tagMatched(tiles:Array):void{
			for(var i:* in tiles){
				_matches.push(ITile(tiles[i]));
			}
		}
		
		public function searchRight(tile:ITile,result:Array):Array{
			searchNeighbour(tile,tile.rightNeighbour,searchRight,result);
			return result;
		}
		
		public function searchLeft(tile:ITile,result:Array):Array{
			searchNeighbour(tile,tile.leftNeighbour,searchLeft,result);
			return result;
		}
		
		public function searchUp(tile:ITile,result:Array):Array{
			searchNeighbour(tile,tile.upNeighbour,searchUp,result);
			return result;
		}
		
		public function searchDown(tile:ITile,result:Array):Array{
			searchNeighbour(tile,tile.downNeighbour,searchDown,result);
			return result;
		}
		
		private function searchNeighbour(tile:ITile,neighbour:ITile,searchDirection:Function,result:Array):void{
			if(neighbour != null && !_searchedTiles.contains(neighbour)){
				if(tile.token != null && neighbour.token != null){
					if(tile.token.equals(neighbour.token)){
						result.push(neighbour);
						_searchedTiles.set(neighbour);
						searchDirection(neighbour,result);
					}
				}
			}
		}
		
	}
}
